﻿using RoadQualityEvalAPI.Helpers;
using RoadQualityEvalAPI.Models;
using RoadQualityEvaluatorData.Domain.Context;
using RoadQualityEvaluatorData.Domain.Entities;
using RoadQualityEvaluatorData.DomainServices.Generic;
using RoadQualityEvaluatorData.DomainServices.Repositories;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;

namespace RoadQualityEvalAPI.Controllers
{
    public class PotholeController : ApiController
    {

        private PotholeRepository _potholeRepository;
        private UserRepository _userRepository;


        public List<PotholeModel> GetAllPotholes()
        {
            var potholes = new List<PotholeModel>();

            _potholeRepository = new PotholeRepository();

            if (_potholeRepository.GetAll().Count > 0)
            {
                foreach (var pot in _potholeRepository.GetAll())
                {
                    potholes.Add(new PotholeModel()
                    {
                        CreatedAt = pot.CreatedAt,
                        Description = pot.Description,
                        Quality = pot.Quality,
                        Type = pot.Type,
                        Location = new LocationModel() { Latitude = pot.Location.Latitude, Longitude = pot.Location.Longitude }
                    });
                }
            }

            return potholes;
        }

        public List<PotholeModel> GetAllPotholesFromUser(string username)
        {
            var potholes = new List<PotholeModel>();

            UnitOfWork uo = new UnitOfWork();

            _potholeRepository = new PotholeRepository(uo);
            _userRepository = new UserRepository(uo);

            var userWhoCollected = _userRepository.GetUserByUsername(username);

            if (_potholeRepository.GetAll().Where(pot => pot.UserWhoCollected.Id == userWhoCollected.Id).Count() > 0)
            {
                foreach (var pot in _potholeRepository.GetAll().Where(pot => pot.UserWhoCollected.Id == userWhoCollected.Id))
                {
                    potholes.Add(new PotholeModel()
                    {
                        CreatedAt = pot.CreatedAt,
                        Description = pot.Description,
                        Quality = pot.Quality,
                        Type = pot.Type,
                        Location = new LocationModel() { Latitude = pot.Location.Latitude, Longitude = pot.Location.Longitude }
                    });
                }
            }

            return potholes;
        }

        public PotholeModel GetPothole(int id)
        {
            _potholeRepository = new PotholeRepository();

            var p = _potholeRepository.GetById(id);

            if (p == null)
                throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.NotFound));


            return new PotholeModel() { Location = new LocationModel() { Latitude = p.Location.Latitude, Longitude = p.Location.Longitude }, Type = p.Type, Quality = p.Quality, Description = p.Description, CreatedAt = p.CreatedAt };
        }

        public PotholeModel GetPotholeByLocation(double latitude, double longitude)
        {
            _potholeRepository = new PotholeRepository();

            var p = _potholeRepository.GetAll().FirstOrDefault(ph => ph.Location.Latitude == latitude && ph.Location.Longitude == longitude);

            if (p == null)
                throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.NotFound));

            return new PotholeModel() { CreatedAt = p.CreatedAt, Description = p.Description, Quality = p.Quality, Type = p.Type, Location = new LocationModel() { Latitude = p.Location.Latitude, Longitude = p.Location.Longitude } };
        }


        [HttpPost]
        public void AddPothole(PotholeModel pothole)
        {
            _potholeRepository = new PotholeRepository();

            if (ModelState.IsValid)
            {
                _potholeRepository.Add(new Pothole()
                {
                    CreatedAt = pothole.CreatedAt,
                    Description = pothole.Description,
                    Quality = pothole.Quality,
                    Type = pothole.Type,
                    Location = new Location() { Latitude = pothole.Location.Latitude, Longitude = pothole.Location.Longitude }
                });

            }
        }


        [HttpPost]
        public void AddPotholeList(List<PotholeModel> potholes)
        {
            UnitOfWork uo = new UnitOfWork();

            _potholeRepository = new PotholeRepository(uo);

            _userRepository = new UserRepository(uo);

            PotholeHelper potHelper = new PotholeHelper(uo);
            
            if (potholes != null && potholes.Count > 0)
            {
                var userWhoCollected = _userRepository.GetUserByUsername(potholes.First().Username);
                
                foreach (var pothole in potholes)
                {
                    
                    Pothole x = new Pothole()
                    {
                        CreatedAt = pothole.CreatedAt,
                        Description = pothole.Description,
                        Quality = pothole.Quality,
                        Type = pothole.Type,
                        Location = new Location() { Latitude = pothole.Location.Latitude, Longitude = pothole.Location.Longitude },
                        UserWhoCollected = userWhoCollected
                    };

                    // check if pothole already exists first (if similar pothole was discovered in a radius of 8 meters)
                    var closestExistingPothole = potHelper.CheckIfPotholeAlreadyExists(x);
                    if (closestExistingPothole == null)
                    {
                        _potholeRepository.Add(x);

                        // assign the pothole to a map section if close enough one exists

                        //TODO: implement assignPot...
                        potHelper.AssignPotholeToMapSection(x);
                    }
                    else
                    {
                        // assing existing pothole greater strength factor
                        closestExistingPothole.Quality++;
                        _potholeRepository.Update(closestExistingPothole);
                    }
                }

                // remove old potholes
                var oldPotholes = _potholeRepository.GetAll().Where(p => (GeneralHelpers.ConvertFromJavaDateStringToDateTime(p.CreatedAt).CompareTo(DateTime.Now.AddDays(-14)) < 0) && p.Quality < 3).ToList();
                
                //TODO: improve here by single access to database for deleting all
                foreach (var p in oldPotholes)
                {
                    _potholeRepository.DeleteById(p.Id);
                }
            }
        }


    }
}
